package com.ifonly.render.renders;

import com.ifonly.ext.freemarker.utils.DirectiveUtils;
import com.ifonly.ext.shiro.ShiroTags;
import com.ifonly.render.Render;
import freemarker.ext.beans.BeansWrapperBuilder;
import freemarker.template.*;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;

/**
 * Freemarker Render
 *
 * @author <a href="mailto:ifonlymaster@163.com">ifonly</a>
 * @version 1.0 2015-12-15 16:15
 * @since JDK 1.6
 */
public class FtlRender extends Render {

    //~~~~~~~~~~~ freemarker ~~~~~~~~~~~
    private static final Configuration config = new Configuration(Configuration.VERSION_2_3_22);

    public static void initFreemarker(ServletContext servletContext, Locale locale, int templateUpdateDelay) {
        // Initialize the FreeMarker configuration;
        // - Create a configuration instance
        // config = new Configuration();
        // - Templates are stoted in the WEB-INF/templates directory of the Web app.
        config.setServletContextForTemplateLoading(servletContext, "/");    // "WEB-INF/templates"
        // - Set update dealy to 0 for now, to ease debugging and testing.
        //   Higher value should be used in production environment.

        com.ifonly.config.Configuration configuration = com.ifonly.config.Configuration.getInstance();
        if (configuration.isDevMode()) {
            config.setTemplateUpdateDelay(0);
        } else {
            config.setTemplateUpdateDelay(templateUpdateDelay);
        }

        // - Set an error handler that prints errors so they are readable with
        //   a HTML browser.
        // config.setTemplateExceptionHandler(TemplateExceptionHandler.HTML_DEBUG_HANDLER);
        config.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);

        // - Use beans wrapper (recommmended for most applications)
        //config.setObjectWrapper(ObjectWrapper.BEANS_WRAPPER);
        config.setObjectWrapper(new BeansWrapperBuilder(Configuration.VERSION_2_3_22).build());
        // - Set the default charset of the template files
        config.setDefaultEncoding(configuration.getEncoding());        // config.setDefaultEncoding("ISO-8859-1");
        // - Set the charset of the output. This is actually just a hint, that
        //   templates may require for URL encoding and for generating META element
        //   that uses http-equiv="Content-type".
        config.setOutputEncoding(configuration.getEncoding());            // config.setOutputEncoding("UTF-8");
        // - Set the default locale
        config.setLocale(locale /* Locale.CHINA */);        // config.setLocale(Locale.US);
        config.setLocalizedLookup(false);

        // 去掉int型输出时的逗号, 例如: 123,456
        // config.setNumberFormat("#");		// config.setNumberFormat("0"); 也可以
        config.setNumberFormat("#0.#####");
        config.setDateFormat("yyyy-MM-dd");
        config.setTimeFormat("HH:mm:ss");
        config.setDateTimeFormat("yyyy-MM-dd HH:mm:ss");

        try {
            config.setSharedVariable("ctx", servletContext.getContextPath());
        } catch (TemplateModelException e) {
            //
        }

        if (configuration.isSecurity()) {
            config.setSharedVariable("shiro", new ShiroTags());
        }

        //设置自定义标签
        DirectiveUtils.exposeRapidMacros(config);
    }

    public FtlRender(String view) {
        this(view, null);
    }

    public FtlRender(String view, String extension) {
        super(view, extension);
    }

    @Override
    public void render() {
        String path = getView();
        PrintWriter out = null;
        try {
            Template template = config.getTemplate(path);
            out = response.getWriter();
            template.process(warpAttrs(), out);
            //template.process(warpRequestAttrs(), out);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (TemplateException e) {
            e.printStackTrace();
        } finally {
            if (out != null)
                out.close();
        }
    }

    private Object warpAttrs() {
        Map<String, Object> results = new HashMap<String, Object>();

        Map<String, Object> requestAttrs = warpRequestAttrs();
        if (requestAttrs != null) {
            results.putAll(requestAttrs);
        }

        Map<String, Object> sessionAttrs = warpSessionAttrs();
        if (sessionAttrs != null) {
            results.putAll(sessionAttrs);
        }

        return results;
    }

    private Map<String, Object> warpRequestAttrs() {
        Enumeration<String> names = request.getAttributeNames();
        if (names != null) {
            Map<String, Object> results = new HashMap<String, Object>();
            while (names.hasMoreElements()) {
                String name = names.nextElement();
                results.put(name, getRequestObject(name, request));
            }
            return results;
        }
        return null;
    }

    private Map<String, Object> warpSessionAttrs() {
        HttpSession session = request.getSession();
        Enumeration<String> names = session.getAttributeNames();
        if (names != null) {
            Map<String, Object> results = new HashMap<String, Object>();
            while (names.hasMoreElements()) {
                String name = names.nextElement();
                results.put(name, getSessionObject(name, session));
            }
            return results;
        }
        return null;
    }

    private Object getSessionObject(String name, HttpSession session) {
        return session.getAttribute(name);
    }

    private Object getRequestObject(String name, HttpServletRequest request) {
        return request.getAttribute(name);
    }

}
